<?php
/**
 * PHP client for requesting reports from JasperServer via SOAP.
 *
 * USAGE:
 *
 * $jasper_url = "http://jasper.example.com/jasperserver/services/repository";
 * $jasper_username = "jasperadmin";
 * $jasper_password = "topsecret";
 *
 *
 * $client = new JasperClient($jasper_url, $jasper_username, $jasper_password);
 *
 * $report_unit = "/my_report";
 * $report_format = "PDF";
 * $report_params = array('foo' => 'bar', 'fruit' => 'apple');
 *
 * $result = $client->requestReport($report_unit, $report_format,$report_params);
 *
 * header('Content-type: application/pdf');
 * echo $result;
 */

class JasperClient {
  private $url;
  private $username;
  private $password;
  
  public function __construct($url, $username, $password) {
    $this->url = $url;
    $this->username = $username;
    $this->password = $password;
  }
  
  public function requestReport($report, $format, $params) {
    $params_xml = "";
    foreach ($params as $name => $value) {
      $params_xml .= "<parameter name=\"$name\"><![CDATA[$value]]></parameter>\n";
    }
    
    $request = "
      <request operationName=\"runReport\" locale=\"en\">
        <argument name=\"RUN_OUTPUT_FORMAT\">$format</argument>
        <resourceDescriptor name=\"\" wsType=\"\"
        uriString=\"$report\"
        isNew=\"false\">
        <label>null</label>
        $params_xml
        </resourceDescriptor>
      </request>
    ";
    
    $client = new SoapClient(null, array(
        'location' => $this->url,
        'uri' => 'urn:',
        'login' => $this->username,
        'password' => $this->password,
        'trace' => 1,
        'exception'=> 1,
        'soap_version' => SOAP_1_1,
        'style' => SOAP_RPC,
        'use' => SOAP_LITERAL

      ));

    $pdf = null;
    try {
      $result = $client->__soapCall('runReport', array(
        new SoapParam($request,"requestXmlString")
      ));
      
      $pdf = $this->parseReponseWithReportData(
        $client->__getLastResponseHeaders(),
        $client->__getLastResponse());
    } catch(SoapFault $exception) {
      $responseHeaders = $client->__getLastResponseHeaders();
      if ($exception->faultstring == "looks like we got no XML document" &&
          strpos($responseHeaders, "Content-Type: multipart/related;") !== false) {
        $pdf = $this->parseReponseWithReportData($responseHeaders, $client->__getLastResponse());
      } else {
        throw $exception;
      }
    }
    
    if ($pdf)
      return $pdf;
    else
      throw new Exception("Jasper did not return PDF data. Instead got: \n$pdf");
  }
  
  protected function parseReponseWithReportData($responseHeaders, $responseBody) {
    preg_match('/boundary="(.*?)"/', $responseHeaders, $matches);
    $boundary = $matches[1];
    $parts = explode($boundary, $responseBody);
      
    $pdf = null;
    foreach($parts as $part) {
      if (strpos($part, "Content-Type: application/pdf") !== false) {
        $pdf = substr($part, strpos($part, '%PDF-'));
        break;
      }
    }
    
    return $pdf;
  }

}

class GenerateReport {

//Properties
private $_wsdlURL;
private $_username;
private $_password;
private $_soapClient;
private $_imageFolder;
private $_reportPath;
private $_reportName;
private $_outputFormat;
private $_parameterArray;


//Constructor
public function __construct() {
    //$config = parse_ini_file('config.ini',true);
    $this->_wsdlURL = 'http://tbsrvdev:8080/jasperserver/services/repository?wsdl';//str_replace("\\", "/", dirname(__FILE__)) . '/' . $config['Jasper']['wsdlURL'];
    $this->_username = 'jasperadmin';//$config['Jasper']['username'];
    $this->_password = 'jasperadmin';//$config['Jasper']['password'];
    $this->_imageFolder = str_replace("\\", "/", dirname(dirname(__FILE__))) . '/images/';
    try {
        $this->_soapClient = new SOAPClient($this->_wsdlURL, array('login' => $this->_username,'password' => $this->_password,'trace' => 1,));
    }
    catch (Exception $e) {
        throw $e;
    }
}

//Methods
public function printReport($reportPath, $reportName, $outputFormat = "HTML", $parameterArray = "") {
    $this->_reportPath = $reportPath;
    $this->_reportName = $reportName;
    $this->_outputFormat = $outputFormat;
    $this->_parameterArray = $parameterArray;

    $requestXML = "<request operationName=\"runReport\">";
    $requestXML .= "<argument name=\"RUN_OUTPUT_FORMAT\">$outputFormat</argument>";
    $requestXML .= "<resourceDescriptor name=\"\" wsType=\"reportUnit\" uriString=\"$reportPath$reportName\" isNew=\"false\">";
    $requestXML .=  "<label></label>";
    foreach ($parameterArray as $key=>$value) {
        $requestXML .= "<parameter name=\"$key\"><![CDATA[$value]]></parameter>";
    }
    $requestXML .= "</resourceDescriptor></request>";
    $params = array("request" => $requestXML );

    $reportOutput = "";
    try {
        $response = $this->_soapClient->runReport($requestXML);
        $reportOutput = $this->parseResponseWithReportData(
            $this->_soapClient->__getLastResponseHeaders(),
            $this->_soapClient->__getLastResponse(),
            $outputFormat
        );
    }//end of try
    catch (SoapFault $e) {
        if ($e->faultstring == 'looks like we got no XML document') {
            $reportOutput = $this->parseResponseWithReportData(
                $this->_soapClient->__getLastResponseHeaders(),
                $this->_soapClient->__getLastResponse(),
                $outputFormat
            );
        }//end of if
        else {
            throw new Exception("Error Creating Report " . $e->faultstring);
        }//end of else
    }//end of catch
    return $reportOutput;
}//end of function

private function parseResponseWithReportData($responseHeaders, $response, $outputFormat) {
    preg_match('/boundary="(.*?)"/', $responseHeaders, $matches);
    $boundary = $matches[1];
    $parts = explode($boundary, $response);
    $reportOutput = "";
    switch ($outputFormat) {
        case 'HTML':
            foreach($parts as $part) {
                if (strpos($part, "Content-Type: image/png") !== false) {
                    $start = strpos($part, "<") + 1;
                    $length = (strpos($part, ">") - $start);
                    $filename = substr($part, $start, $length) . '.png';
                    $file = fopen("$this->_imageFolder$filename","wb");
                    $contentStart = strpos($part, "PNG") - 1;
                    $contentLength = (strpos($part, "--") - $contentStart) + 1;
                    $contents = substr($part, $contentStart, $contentLength);
                    fwrite($file, $contents);
                    fclose($file);
                }
                if (strpos($part, "Content-Type: image/gif") !== false) {
                    $start = strpos($part, "<") + 1;
                    $length = (strpos($part, ">") - $start);
                    $filename = substr($part, $start, $length) . '.gif';
                    $file = fopen("$this->_imageFolder$filename","wb");
                    $contentStart = strpos($part, "GIF");
                    $contentLength = (strpos($part, "--") - $contentStart) + 1;
                    $contents = substr($part, $contentStart, $contentLength);
                    fwrite($file, $contents);
                    fclose($file);
                }
                if (strpos($part, "Content-Type: text/html") !== false) {
                    $contentStart = strpos($part, '<html>');
                    $contentLength = (strpos($part, '</html>') - $contentStart) + 7;
                    $reportOutput = substr($part, $contentStart, $contentLength);
                }
            }//end of for each
            break;
        case 'PDF':
            foreach($parts as $part) {
                if (strpos($part, "Content-Type: application/pdf") !== false) {
                    $reportOutput = substr($part, strpos($part, '%PDF-'));
                    break;
                }
            } //end of foreach
            break;
        case 'XLS':
            foreach($parts as $part) {
                if (strpos($part, "Content-Type: application/xls") !== false) {
                    $reportOutput = substr($part, (strpos($part, '<report>') + 9));
                    break;
                }
            }
        case 'CSV':
            foreach($parts as $part) {
                if (strpos($part, "Content-Type: application/vnd.ms-excel") !== false) {
                    $contentStart = strpos($part, 'Content-Id: <report>') + 24;
                    $reportOutput = substr($part, $contentStart);
                    break;
                }
            }
    }
    return $reportOutput;
}//end of functoin

}//end of class
